home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr26 / termcap.zip / TERMCAP.C next >
C/C++ Source or Header  |  1993-05-01  |  21KB  |  675 lines

  1. /*    termcap.c    880204    NHA    */
  2. /* My implementation of the termcap(3X) library routines.
  3.  * All specs lifted straight from 4.3bsd Programmers Reference Manual.
  4.  * These functions extract and use capabilities from the terminal
  5.  * capability database termcap(5).  These are low level routines;
  6.  * see curses(3X) for a higher level package.
  7.  ** You'll find it looks a lot nicer if you use a tab interval of 4.
  8.  */
  9.  
  10. #define    DEBUG    0
  11.  
  12. #if DEBUG
  13. #define    MAJOR    'L'                            /* major module identifier */
  14. #define    MINOR    'T'                            /* minor module identifier */
  15. #include    <gen.h>                            /* my all-purpose include file */
  16. #else DEBUG
  17. #include    <stdio.h>
  18. #include    <fcntl.h>
  19. #define        export
  20. #define        import        extern
  21. #define        local        static
  22. #define        bool        int
  23. #define        abs(x)        ( (x < 0) ? (-(x)) : (x) )
  24. #define        YES            1
  25. #define        NO            0
  26. #define        error(s)    {perror(s);  exit(99);}
  27. #define        initdebug(pac, pav, confile, listfile, initstring)
  28. static        printd(lvl, fmt) {}
  29. #endif DEBUG
  30.  
  31. #define    BUFSIZE    1024
  32.  
  33. /* external variables (supplied by user) required by this package */
  34. import char        PC;                            /* pad char, default ^@ */
  35. import char        BC;                            /* backspace char if not ^H */
  36. import char        UP;                            /* char for Upline (cursor up) */
  37. import char        ospeed;                        /* output speed, see stty(3) */
  38.  
  39. #ifdef __STDC__
  40. import char        *getenv(char *id);
  41. import int        open(char *name, unsigned mode);
  42. import unsigned    strlen(char *str);
  43. import unsigned    strspn(char *str1, char *str2);
  44. import int        strcmp(char *str1, char *str2);
  45. import int        strncmp(char *str1, char *str2, unsigned n);
  46. import char        *strncpy(char *buf, char *str, unsigned n);
  47. import char        *strchr(char *string, char ch);
  48. import char        *strpbrk(char *string, char *delimiters);
  49. #else __STDC__
  50. import char        *getenv();
  51. import int        open();
  52. import unsigned    strlen();
  53. import unsigned    strspn();
  54. import int        strcmp();
  55. import int        strncmp();
  56. import char        *strncpy();
  57. import char        *strchr();
  58. import char        *strpbrk();
  59. #endif __STDC__
  60.  
  61. /* milliseconds per character, for each of the possible baud rates of ospeed */
  62. /* here multiplied by 10 for computational convenience */
  63. local unsigned    delayFactor[] = {
  64.                                    0,        /* B0 */    /* hang up dataphone */
  65.                                 1920,        /* B50 */
  66.                                 1280,        /* B75 */
  67.                                  872,        /* B110 */
  68.                                  730,        /* B134 */
  69.                                  640,        /* B150 */
  70.                                  480,        /* B200 */
  71.                                  320,        /* B300 */
  72.                                  160,        /* B600 */
  73.                                   80,        /* B1200 */
  74.                                   50,        /* B1800 */
  75.                                   40,        /* B2400 */
  76.                                   20,        /* B4800 */
  77.                                   10,        /* B9600 */
  78.                                    5,        /* EXTA (19200 here) */
  79.                                    2,        /* EXTB (34800 here) */
  80.                                 };
  81. /* remember where user's terminal entry buffer is */
  82. local char        *ebuf = NULL;                /* pointer to entry buffer */
  83.  
  84.  
  85.  
  86. /*+        f i n d C a p
  87.  * Returns pointing to the character immediately following the capability id.
  88.  * Returns NULL if tgetent() has not yet been called successfully.
  89.  * Returns NULL if capability not found.
  90.  */
  91. local char *findCap(id)
  92. char    *id;                                /* name of the capability to find */
  93.     {
  94.     char    *p;                                /* pointer into the entry buffer */
  95.  
  96.     printd(5, "findCap(\"%s\"), ebuf=%p\n", id, ebuf);
  97.     if (ebuf == NULL)
  98.         return NULL;
  99.     for (p = ebuf   ;   *p   ;   ++p)
  100.         {
  101.         printd(9, " %02x", *p);
  102.         if ( (p[0] == ':')  &&  (p[1] == id[0])  &&  (p[2] == id[1]) )
  103.             {
  104.             printd(7, "findCap(): SUCCESS, p=%.15s...\n", p);
  105.             p = &p[3];
  106.             break;
  107.             }
  108.         }
  109.     if ( ! *p)
  110.         p = NULL;
  111.     printd(5, "findCap(): returning %p (%.11s...)\n", p, p);
  112.     return p;
  113.     }
  114.  
  115.  
  116.  
  117. /*+        g e t E n t r y
  118.  * Gets the named entry from the already-opened termcap file into the buffer.
  119.  * The size of the buffer is BUFSIZE, and it is considered to be an
  120.  * error if the size of the entry equals or exceeds this.
  121.  * We place a terminating NULL character at the end of the entry.
  122.  * Call error() on any irregularities.
  123.  * Return 0 if the named entry not found, else 1.
  124.  * Removes terminal names and all newlines from the entry.
  125.  **If this is called for a 2nd time from tgetent(), then the length checking
  126.  **is useless.
  127.  */
  128. local int getEntry(fd, outbuf, name)
  129. int        fd;                                    /* FileDescriptor for termcap file*/
  130. char    *outbuf;                            /* where we put the entry */
  131. char    *name;                                /* terminal type name we seek */
  132.     {
  133.     unsigned    namlen;                        /* # chars in name */
  134.     int            cnt;                        /* # unprocessed chars in inbuf[] */
  135.     char        *ip;                        /* pointer into input buffer */
  136.     char        *op;                        /* pointer into output buffer */
  137.     char        *ptmp;                        /* temporary pointer */
  138.     int            stat;                        /* status of read(), etc */
  139.     char        inbuf[BUFSIZE];                /* termcap file is read into here */
  140.  
  141.     printd(5, "getEntry(%d, %p, \"%s\")\n", fd, inbuf, name);
  142.     op = outbuf;
  143.     namlen = strlen(name);
  144.     cnt = read(fd, inbuf, BUFSIZE-1);
  145.     if (cnt == -1)
  146.         error("getEntry(): file is empty\n");
  147.     inbuf[cnt] = '\0';                        /* maintain inbuf[] as a string */
  148.     for (ip = inbuf   ;   0 < cnt   ;   ++ip, --cnt)
  149.         {
  150.         printd(7, "cnt=%d, ip='%.55s...'\n", cnt, ip);
  151.         stat = strspn(ip, "\r\n \t\b\f");
  152.         if (0 < stat)
  153.             {
  154.             printd(8, "skipping %d whitespace characters\n", stat);
  155.             ip = &ip[--stat];
  156.             cnt -= stat;
  157.             }
  158.         else if (*ip == '#')
  159.             {
  160.             printd(6, "comment line '%.11s...'\n", ip);
  161.             ptmp = ip;
  162.             ip = strchr(ip, (char)'\n');
  163.             cnt  -=  (ip == NULL) ? cnt : (int)(ip - ptmp);
  164.             }
  165.         else if (strncmp(name, ip, namlen) == 0)
  166.             {
  167.             printd(6, "getEntry(): SUCCESS, ip = '%.22s...', cnt=%u\n", ip,cnt);
  168.             ip = strchr(ip, (char)':');        /* skip over namelist */
  169.             printd(7, "getEntry(): raw entry is: '%s'\n", ip);
  170.             /* copy entry into output buffer */
  171.             /* eliminate non-space whitespace and continuation \ */
  172.             for (op = outbuf   ;   ip != NULL  &&  *ip != '\0'   ;   ++ip)
  173.                 {
  174.                 printd(9, " %02x", *ip);
  175.                 if (ip[0] == '\\'   &&   ip[1] == '\r'   &&   ip[2] == '\n')
  176.                     ip = &ip[2];
  177.                 else if (ip[0] == '\\'   &&   ip[1] == '\n')
  178.                     ++ip;
  179.                 else if (strchr("\t\r\b\f", *ip) != NULL)
  180.                     continue;
  181.                 else if (*ip == '\n')
  182.                     break;
  183.                 else
  184.                     *op++  =  *ip;
  185.                 }
  186.             if (*ip != '\n')
  187.                 error("getEntry(): entry too long\n");
  188.             *op = '\0';
  189.             printd(6, "getEntry(): outbuf='%s'\n", outbuf);
  190.             printd(5, "getEntry(): returning 1  [SUCCESS]\n");
  191.             return 1;
  192.             }
  193.         else
  194.             {                                /* advance to next name in list */
  195.             ptmp = ip;
  196.             ip = strpbrk(ip, "|:");            /* find name delimiter */
  197.             if (ip == NULL)
  198.                 error("getEntry(): bad format\n");
  199.             cnt -= ip - ptmp;
  200.             if (*ip != '|')
  201.                 {                            /* at end of namelist for entry */
  202.                 /* dispose of entire entry */
  203.                 printd(8, "end of namelist, cnt=%d\n", cnt);
  204.                 for (++ip, --cnt   ;   0 < cnt   ;   ++ip, --cnt)
  205.                     if ( ip[0] == '\n'   && 
  206.                           ( (ip[-1] == '\r'  &&   ip[-2] != '\\')
  207.                                               ||
  208.                             (ip[-1] != '\r'  &&   ip[-1] != '\\') )
  209.                        )
  210.                         {                /* skip to next entry in file */
  211.                         /* delete this entry from inbuf */
  212.                         for (ptmp = inbuf   ;   *ip != '\0'   ;   ++ptmp, ++ip)
  213.                             *ptmp = *ip;
  214.                         *ptmp = *ip;        /* string stopper character */
  215.                         ip = inbuf;
  216.                         if (strlen(ip) != cnt)
  217.                             error("getEntry(): bad strlen(ip)\n");
  218.                         /* fill inbuf with more characters */
  219.                         stat = read(fd, ptmp, BUFSIZE - cnt - 1);
  220.                         if (0 < stat)
  221.                             {
  222.                             cnt += stat;
  223.                             inbuf[cnt] = '\0';
  224.                             }
  225.                         break;
  226.                         }
  227.                 if (cnt <= 0)
  228.                     error("getEntry(): entry too long!\n");
  229.                 }
  230.             }
  231.         }
  232.     outbuf[0] = '\0';                        /* not found */
  233.     printd(6, "getEntry(): outbuf='%s'\n", outbuf);
  234.     printd(5, "getEntry(): returning 0  [FAILURE]\n");
  235.     return 0;
  236.     }
  237.  
  238.  
  239.     
  240. /*+        t g e t e n t
  241.  * Extracts the entry for terminal name into the buffer at bp.
  242.  * Bp should be a character array of size 1024 and must be retained through
  243.  * all subsequent calls to tgetnum(), tgetflag(), and tgetstr().
  244.  * Returns -1 if it cannot open the termcap file, 0 if the terminal name
  245.  * given does not have an entry, and 1 if all goes well.
  246.  * Looks in the environment for a TERMCAP variable.  If found, and the value
  247.  * does not begin with a slash, and the terminal type name is the same as
  248.  * the environment string TERM, the TERMCAP string is used instead of reading
  249.  * the termcap file.  If it does begin with a slash, the string is used
  250.  * as a pathname rather than /etc/termcap.  This can speed up entry into
  251.  * programs that call tgetent(), as well as to help debug new terminal
  252.  * descriptions  or to make one for your terminal if you can't write the
  253.  * file /etc/termcap.
  254.  */
  255. export int tgetent(bp, name)
  256. char    *bp;                                /* pointer to user's buffer */
  257. char    *name;                                /* terminal type name */
  258.     {
  259.     char    *termcap;                        /* pointer to $TERMCAP string */
  260.     int        fd;                                /* File Descriptor, termcap file */
  261.     int        retval;                            /* return value */
  262.     
  263.     printd(3, "tgetent(%p, \"%s\")\n", bp, name);
  264.     termcap = getenv("TERMCAP");
  265.     if (termcap != NULL   &&   termcap[0] != '/'   &&
  266.         strcmp(name, getenv("TERM")) == 0)
  267.         {                                    /* use $TERMCAP as the entry */
  268.         printd(6, "tgetent(): using contents of $EXINIT\n");
  269.         strncpy(bp, termcap, (BUFSIZE-1));
  270.         bp[BUFSIZE] = '\0';
  271.         termcap = "/etc/termcap";            /* in case :tc capability found */
  272.         retval = 1;
  273.         }
  274.     else
  275.         {                                    /* look for entry in termcap file */
  276.         if (termcap[0] != '/')
  277.             termcap = "/etc/termcap";        /* use default termcap file */
  278.         printd(6, "tgetent(): opening file %s\n", termcap);
  279.         fd = open(termcap, O_RDONLY);
  280.         if (fd == -1)
  281.             retval = -1;
  282.         else
  283.             {
  284.             retval = getEntry(fd, bp, name);
  285.             close(fd);
  286.             }
  287.         }
  288.     if (retval == 1)
  289.         ebuf = bp;                            /* for our use in future pkg calls*/
  290.     
  291.     /* deal with the :tc= capability */
  292.     bp = findCap("tc");
  293.     if (bp != NULL)
  294.         {
  295.         char    newname[88];
  296.         
  297.         printd(6, "tgetent(): :tc found at %p, is '%s'\n", &bp[-3], &bp[-3]);
  298.         strncpy(newname, &bp[1], sizeof newname);
  299.         if (strchr(newname, (char)':') != NULL)
  300.             *(strchr(newname, (char)':'))  =  '\0';
  301.         fd = open(termcap, O_RDONLY);
  302.         if (fd == -1)
  303.             {
  304.             printd(2, "tgetent(%s): can't open :tc file '%s'\n", name, newname);
  305.             retval = -1;
  306.             }
  307.         else
  308.             {
  309.             retval = getEntry(fd, &bp[-2], newname);
  310.             close(fd);
  311.             }
  312.         }
  313.         
  314.     printd(3, "tgetent(): returning %d\n", retval);
  315.     return retval;
  316.     }
  317.  
  318.  
  319.     
  320. /*+        t g e t n u m
  321.  * Gets the numeric value of capability id, returning -1 if it is not given
  322.  * for the terminal.
  323.  */
  324. export int tgetnum(id)
  325. char    *id;                                /* capability name */
  326.     {
  327.     int        retval;
  328.     char    *p;
  329.  
  330.     printd(3, "tgetnum(\"%s\")\n", id);
  331.     p = findCap(id);
  332.     if (p == NULL   ||   *p != '#')
  333.         retval = -1;                        /* not found, or not numeric */
  334.     else
  335.         {
  336.         retval = 0;
  337.         for (++p   ;   *p != ':'   ;   ++p)
  338.             retval  =  (retval * 10) + (*p - '0');
  339.         }
  340.     printd(3, "tgetnum(): returning %d\n", retval);
  341.     return retval;
  342.     }
  343.  
  344.  
  345.  
  346. /*+        t g e t f l a g
  347.  * Returns 1 if the specified capability is present in the terminal's entry,
  348.  * 0 if it is not.
  349.  **This implementation requires that the capability be a boolean one.
  350.  */
  351. export int tgetflag(id)
  352. char    *id;                                /* capability name */
  353.     {
  354.     int        retval;
  355.     char    *p;
  356.  
  357.     printd(3, "tgetflag(\"%s\")\n", id);
  358.     p = findCap(id);
  359.     retval  =  (p != NULL  &&  *p == ':');
  360.     printd(3, "tgetflag(): returning %d\n", retval);
  361.     return retval;
  362.     }
  363.  
  364.  
  365.  
  366. /*+        t g e t s t r
  367.  * Returns the string value of the capability id, places it in the buffer
  368.  * at area, and advances the area pointer [past the terminating '\0' char].
  369.  * It decodes the abbreviations for this field described in termcap(5),
  370.  * except for cursor addressing and padding information.
  371.  * Returns NULL if the capability was not found.
  372.  */
  373. export char *tgetstr(id, area)
  374. char    *id;                                /* capability name */
  375. char    **area;                                /* pointer to output pointer */
  376.     {
  377.     char        *retval;                    /* return value */
  378.     char        *p;                            /* pointer into capability string */
  379.     unsigned    sum;                        /* for chars given in octal */
  380.  
  381.     printd(3, "tgetstr(\"%s\", %p): *area=%p\n", id, area, *area);
  382.     p = findCap(id);
  383.     if (p == NULL   ||   *p != '=')
  384.         retval = NULL;
  385.     else
  386.         {
  387.         retval = *area;
  388.         for (++p   ;   *p != ':'   ;   ++p)
  389.             {
  390.             printd(9, "p=%p,  *p=%02x\n", p, *p);
  391.             if (*p == '\\')
  392.                 switch (*++p)
  393.                     {                        /* special */
  394.                 case '0': case '1': case '2': case '3':
  395.                 case '4': case '5': case '6': case '7':
  396.                     sum = (p[0] - '0') << 6  +
  397.                           (p[1] - '0') << 3  +
  398.                           (p[2] - '0');
  399.                     ++p;
  400.                     ++p;
  401.                     *(*area)++  =  (char)(sum & 0377);
  402.                     /** will \200 really end up as \000 like it should ? **/
  403.                     /** see termcap(5), top of page 6 **/
  404.                     break;
  405.                 case '^':    *(*area)++  =  '^';        break;
  406.                 case '\\':    *(*area)++  =  '\\';    break;
  407.                 case 'E':    *(*area)++  =  '\033';    break;        /* escape */
  408.                 case 'b':    *(*area)++  =  '\b';    break;
  409.                 case 'f':    *(*area)++  =  '\f';    break;
  410.                 case 'n':    *(*area)++  =  '\n';    break;
  411.                 case 'r':    *(*area)++  =  '\r';    break;
  412.                 case 't':    *(*area)++  =  '\t';    break;
  413.                 default:    *(*area)++  =  *p;        break;
  414.                     }
  415.             else if (*p == '^')
  416.                 *(*area)++  =  *++p - '@';    /* control */
  417.             else
  418.                 *(*area)++  =  *p;            /* normal */
  419.             }
  420.         *(*area)++ = '\0';                    /* NULL-terminate the string */
  421.         }
  422.     printd(3, "tgetstr(): returning ");
  423.     if (retval == NULL)
  424.         {                                    /* these must be here for print() */
  425.         printd(3, "NULL");
  426.         }                                    /* these must be here for print() */
  427.     else
  428.         {
  429.         printd(3, "%p  [", retval);
  430.         for (p = retval   ;   p != *area   ;   ++p)
  431.             printd(3, " %02x", (unsigned)*p);
  432.         printd(3, "]");
  433.         }
  434.     printd(3, ",  *area=%p\n",  *area);
  435.     return retval;
  436.     }
  437.  
  438.  
  439.     
  440. /*+        t g o t o
  441.  * Returns a cursor addressing string decoded from cm to go to column destcol
  442.  * in line destline. It uses the external variables UP (from the up capability)
  443.  * and BC (if bc is given rather than bs) if necessary to avoid placing
  444.  * \n, ^D, or ^@ in the returned string.  (Programs which call tgoto() should
  445.  * be sure to turn off the XTABS bit(s), since tgoto() may not output a tab.
  446.  * Note that programs using termcap should in general turn off XTABS anyway
  447.  * since some terminals use control I for other functions, such as non-
  448.  * destructive space.)  If a % sequence is given which is not understood,
  449.  * then tgoto() returns "OOPS".
  450.  **Output buffer is local, so don't try any recursion.
  451.  **No error checking here.
  452.  */
  453. export char *tgoto(cm, destcol, destline)
  454. char    *cm;                                /* cm capability string */
  455. int        destcol;                            /* destination column (left is 0) */
  456. int        destline;                            /* destination line (top is 0) */
  457.     {
  458.     char        *outp;                        /* pointer into answer[] */
  459.     local char    answer[88];                    /* result stashed here */
  460.     bool        reversed;                    /* YES when should send col 1st */
  461.     int            value;                        /* next value to output */
  462.  
  463.     printd(3, "tgoto(\"%s\", %d, %d)\n", cm, destcol, destline);
  464.     reversed = NO;
  465.     value = destline;
  466.     outp = answer;
  467.     for (   ;   *cm   ;   ++cm)
  468.         {
  469.         printd(9, " %02x", *cm);
  470.         if (*cm == '%')
  471.             {
  472.             switch (*++cm)
  473.                 {
  474.             case '%':    *outp++ = '%';
  475.                         break;
  476.             case 'd':    sprintf(outp, "%d", value);
  477.                         if (value < 0)
  478.                             ++outp;
  479.                         ++outp;
  480.                         if (9 < abs(value))
  481.                             ++outp;
  482.                         if (99 < abs(value))
  483.                             ++outp;
  484.                         value = (reversed) ? destline : destcol;
  485.                         break;
  486.             case '2':    sprintf(outp, "%02d", value);
  487.                         outp += 2;
  488.                         value = (reversed) ? destline : destcol;
  489.                         break;
  490.             case '3':    sprintf(outp, "%03d", value);
  491.                         outp += 3;
  492.                         value = (reversed) ? destline : destcol;
  493.                         break;
  494.             case '.':    *outp++ = value;
  495.                         value = (reversed) ? destline : destcol;
  496.                         break;
  497.             case '+':    *outp++ = value + *++cm;
  498.                         value = (reversed) ? destline : destcol;
  499.                         break;
  500.             case '>':    if (value > *++cm)
  501.                             value += *++cm;
  502.                         else
  503.                             ++cm;
  504.                         break;
  505.             case 'r':    value = (reversed) ? destline : destcol;
  506.                         reversed ^= YES;
  507.                         break;
  508.             case 'i':    ++value;
  509.                         break;
  510.             case 'n':    destcol  ^= 0140;
  511.                         destline ^= 0140;
  512.                         break;
  513.             case 'B':    value = (16 * (value / 10))  +  (value % 10);
  514.                         break;
  515.             case 'D':    value = (value - (2 * (value % 16)));
  516.                         break;
  517.             default:    sprintf(outp, "OOPS");
  518.                         outp += 4;
  519.                         break;
  520.                 }
  521.             printd(8, "reversed=%b, value=%d\n", reversed, value);
  522.             }
  523.         else
  524.             *outp++ = *cm;
  525.         }
  526.     *outp = '\0';
  527.     printd(3, "tgoto(): returning '%s'\n", answer);
  528.     return answer;
  529.     }
  530.  
  531.  
  532.  
  533. /*+        t p u t s
  534.  * Decodes the leading pad information of the string cp; affcnt gives the
  535.  * number of lines affected by the operation, or 1 if this is not applicable.
  536.  * Outc is a routine which is called with each character in turn.
  537.  * The external variable ospeed should contain the output speed of
  538.  * the terminal as encoded by stty(3).
  539.  * The external variable PC should contain a pad character to be used
  540.  * (from the pc capability) if a null (^@) is inappropriate.
  541.  */
  542. export void tputs(cp, affcnt, outc)
  543. char    *cp;                                /* leading pad information string */
  544. int        affcnt;                                /* number lines affected, or 1 */
  545. int        (*outc)();                            /*output function to call per char*/
  546.     {
  547.     char        *p;
  548.     bool        decimalFlag;                /* delay had a decimal point */
  549.     unsigned    delay;
  550.     unsigned    cnt;
  551.     
  552.     printd(3, "tputs(\"%s\", %d, %p):  ospeed=%u\n", cp, affcnt, outc, ospeed);
  553.  
  554.     /* calculate delay, if any */
  555.     /* currently no guard against having more than 1 digit after decimal point*/
  556.     decimalFlag = NO;
  557.     delay = 0;
  558.     for (p = cp   ;   strchr("0123456789.", *p)   ;   ++p)
  559.         if (*p == '.')
  560.             decimalFlag = YES;
  561.         else
  562.             delay  =  (delay * 10) + (*p - '0');
  563.     if ( ! decimalFlag)
  564.         delay *= 10;                        /* units are really 10ms */
  565.     if (*p == '*')
  566.         delay *= affcnt;
  567.     printd(6, "tputs(): delay = %u.%u milliseconds\n", delay/10, delay%10);
  568.     delay += (delayFactor[ospeed] + 1) / 2;    /* round up */
  569.     delay /= delayFactor[ospeed];
  570.     printd(5, "tputs(): delay = %u characters,  [delayFactor is %u]\n",
  571.       delay, delayFactor[ospeed]);
  572.  
  573.     for (   ;   *cp != '\0'   ;   ++cp)
  574.         outc(*cp);                            /* output string */
  575.     for (cnt = delay   ;   cnt   ;   --cnt)
  576.         outc(PC);                            /* output delay characters */
  577.     printd(3, "tputs(): returning\n");
  578.     }
  579.  
  580.  
  581.  
  582. #if        TEST
  583.  
  584. export char        PC;                            /* pad char, default ^@ */
  585. export char        BC;                            /* backspace char if not ^H */
  586. export char        UP;                            /* char for Upline (cursor up) */
  587. export char        ospeed = 13;                /* output speed, see stty(3) */
  588.  
  589. local char    buf[1024];                        /* holds termcap entry */
  590. local char    strbuf[512];                    /* for output of tgetstr() */
  591. local char    *strptr;                        /* ptr to strbuf[] */
  592.  
  593.  
  594. /*+        o c
  595.  * Tiny test routine to simulate putting out a character.
  596.  */
  597. local void oc(c)
  598. char    c;
  599.     {
  600.     putc(c, stdout);
  601.     }
  602.  
  603.  
  604. /*+        m a i n
  605.  * Test program for the termcap routines.
  606.  * Command line parameters:
  607.  *    1st is terminal name, defaulted to "mono".
  608.  *    2nd is name of numeric capability, default "co".
  609.  *    3rd is name of boolean capability, default "bs".
  610.  *    4th is name of string capability, default "so".
  611.  *    5th is test string for tgoto(), default is "6\\E&%r%2c%2Y".
  612.  *    6th is test string for tputs(), default is "3.5*123".
  613.  */
  614. export int main(ac, av)
  615. int        ac;
  616. char    **av;
  617.     {
  618.     int        stat;                            /* integer return value */
  619.     char    *instr;                            /* input string value */
  620.     char    *outstr;                        /* string return value */
  621.     char    *ttype;                            /* terminal type string */
  622.     char    *capability;                    /* capability name string */
  623.     
  624.     /* setup */
  625.     initdebug(&ac, &av, "/dev/con", "debug.out", "LB3LT8");
  626.     PC = '@';
  627.     BC = 'H';
  628.     UP = 'B';
  629.     
  630.     /* test tgetent() */
  631.     ttype = (ac < 2) ? "mono" : av[1];
  632.     stat = tgetent(buf, ttype);
  633.     printf("main: tgetent(buf, \"%s\") returned %d\n", ttype, stat);
  634.     if (stat != 1)
  635.         exit (99);
  636.         
  637.     /* test tgetnum() */
  638.     capability = (ac < 3) ? "co" : av[2];
  639.     stat = tgetnum(capability);
  640.     printf("main: tgetnum(%s) returned %d\n", capability, stat);
  641.  
  642.     /* test tgetflag() */
  643.     capability = (ac < 4) ? "bs" : av[3];
  644.     stat = tgetflag(capability);
  645.     printf("main: tgetflag(%s) returned %d\n", capability, stat);
  646.  
  647.     /* test tgetstr() */
  648.     capability = (ac < 5) ? "so" : av[4];
  649.     strptr = strbuf;
  650.     outstr = tgetstr(capability, &strptr);
  651.     printf("main: tgetstr(%s, 0x%lx) returned '%s'  [strbuf=0x%lx, strptr=0x%lx]\n",
  652.       capability, &strptr, outstr, strbuf, strptr);
  653.     if (strcmp(capability, "so") == 0)
  654.         {
  655.         strptr = strbuf;
  656.         tgetstr("se", &strptr);
  657.         printf(strbuf);
  658.         }
  659.  
  660.     /* test tgoto() */
  661.     instr = (ac < 6) ? "6\\E&%r%2c%2Y" : av[5];
  662.     outstr = tgoto(instr, 12, 3);
  663.     printf("main: tgoto(\"%s\", 12, 3) returned '%s'\n", instr, outstr);
  664.     
  665.     /* test tputs() */
  666.     instr = (ac < 7) ? "3.5*123" : av[6];
  667.     printf("main: tputs(\"%s\", 3, oc) returned '", instr);
  668.     tputs(instr, 3, oc);
  669.     printf("'\n");
  670.     
  671.     return 0;
  672.     }
  673.  
  674. #endif    TEST
  675.